<html>
	<head> 
		<title>My First Platformer</title>
	</head>
	<body onload="init()">
		<div id="mousedebug" style="width: 500px; height: 20px;"></div>
		<div>
			<canvas id="canvas" width="800" height="400" style="background-color:#333333;"></canvas>
		</div>	
		<div id="debug" style="overflow: scroll; width: 400px; height: 200px;">
			<br><div id ="circledebug"></div>
			<br><div id ="squaredebug"></div>
		</div>
		<div id="scroll"/>
	</body>

	<script type="text/javascript" src="../lib/Box2dWeb-2.1.a.3.min.js"></script>
	<script type="text/javascript" src="../lib/jquery-1.9.0.min.js"></script>
	<script type="text/javascript">

	$('#scroll').hide();
		
	function init() {
		// define classes being used
		var 	b2Vec2 = Box2D.Common.Math.b2Vec2,
			b2AABB = Box2D.Collision.b2AABB,
			b2Body = Box2D.Dynamics.b2Body,
			b2BodyDef = Box2D.Dynamics.b2BodyDef,
			b2FixtureDef = Box2D.Dynamics.b2FixtureDef,
			b2Fixture = Box2D.Dynamics.b2Fixture,
			b2World = Box2D.Dynamics.b2World,
			b2MassData = Box2D.Collision.Shapes.b2MassData,
			b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape,
			b2CircleShape = Box2D.Collision.Shapes.b2CircleShape,
			b2DebugDraw = Box2D.Dynamics.b2DebugDraw,
			b2ContactListener = Box2D.Dynamics.b2ContactListener,
			b2WorldManifold = Box2D.Collision.b2WorldManifold,
			b2Manifold = Box2D.Collision.b2Manifold,
			b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef; 
		
		// constants

		var worldscale = 30.0;
		var canvas_x = 800;
		var canvas_y = 400;

		var world_width = 1000/worldscale;
		var world_height = 400/worldscale;

		// create world 
		var world = new b2World( 
			new b2Vec2(0,10),
			false
		);

		
		var bounds_fixDef = new b2FixtureDef; // fixture def for world walls
		bounds_fixDef.friction = 0.6;
		bounds_fixDef.density = 0.1;
		bounds_fixDef.restitution = 0.01;
		bounds_fixDef.userData = "ground";

		// create ground
		var bounds_bodyDef = new b2BodyDef; 

		bounds_bodyDef.type = b2Body.b2_staticBody;
		bounds_fixDef.shape = new b2PolygonShape;
		// ground
		bounds_fixDef.shape.SetAsBox(world_width,30/worldscale);
		bounds_bodyDef.position.Set( world_width/2, world_height);  
		world.CreateBody(bounds_bodyDef).CreateFixture(bounds_fixDef);
		bounds_fixDef.userData = "wall";
		// left end of world
		bounds_fixDef.shape.SetAsBox(30/worldscale, world_height);
		bounds_bodyDef.position.Set( 0, canvas_y/2/worldscale );  
		world.CreateBody(bounds_bodyDef).CreateFixture(bounds_fixDef);
		// right end of world
		bounds_bodyDef.position.Set( world_width, canvas_y/2/worldscale );  
		world.CreateBody(bounds_bodyDef).CreateFixture(bounds_fixDef);

		// create foating body
		bounds_fixDef.shape.SetAsBox(70/worldscale,20/worldscale);
		bounds_bodyDef.position.Set( world_width/2, canvas_y/2/worldscale );  
		world.CreateBody(bounds_bodyDef).CreateFixture(bounds_fixDef);
	
		// player definitions
		var player = function(x,y) {
			this.type = "player";
			var fixDef = new b2FixtureDef;
			fixDef.friction = 0.6;
			fixDef.density = 4;
			fixDef.restitution = 0.0;
			fixDef.userData = "player";

			var bodyDef = new b2BodyDef;
			bodyDef.type = b2Body.b2_dynamicBody;
			fixDef.shape = new b2CircleShape;
			fixDef.shape.SetRadius(20/worldscale);
			
			if( x == null )
				bodyDef.position.x = canvas_x/2/worldscale;	
			else 
				bodyDef.position.x = x;
			if( y == null )
				bodyDef.position.y = canvas_y/2/worldscale;	
			else 
				bodyDef.position.y = y;

			this.body = world.CreateBody(bodyDef);
			this.fixture = this.body.CreateFixture(fixDef);
			this.canJump = false;
		};
		player.prototype.move = function() {
			
			var edge_list = this.body.GetContactList();

			var max_velocity = 2;
			var force_mag = 25; 
			var force = new b2Vec2();

			// handle player moving	
			var vel = this.body.GetLinearVelocity();

			if(keys[37]){ // left
				force.x = -1*force_mag; 
				lastX = this.body.GetPosition().x;
				steps=0;
			}
			if(keys[39]){ //right
				force.x = 1*force_mag;
				lastX = this.body.GetPosition().x;
				steps=0;
			}
			if(keys[38]){ //jump
				if( this.canJump ) {
					vel.y = -500/worldscale;
				}
			}
			
			var opposite_force = new b2Vec2(0,0);
			opposite_force.x = -1 * force.x;
			
			this.body.ApplyForce(force, this.body.GetWorldCenter());
			this.body.SetLinearDamping(1.5);
		};


		// create enemy 

		var enemy = function(x,y) {
			var mybodyDef = new b2BodyDef;		
			var myfixDef = new b2FixtureDef;
			this.type = "enemy";
			myfixDef.friction = 0.0;
			myfixDef.density = 1;
			myfixDef.restitution = 0;
			myfixDef.userData = "enemy";
			mybodyDef.type = b2Body.b2_dynamicBody;
			myfixDef.shape = new b2PolygonShape;
			myfixDef.shape.SetAsBox(30/worldscale,30/worldscale);
			if( x == null )
				mybodyDef.position.x = canvas_x/4/worldscale;	
			else 
				mybodyDef.position.x = x;
			if( y == null )
				mybodyDef.position.y = canvas_y/2/worldscale;	
			else 
				mybodyDef.position.y = y;
				
			this.body = world.CreateBody(mybodyDef);
			this.fixture = this.body.CreateFixture(myfixDef);
			this.body.SetLinearVelocity(new b2Vec2(1,0));
			this.minVelocity = 1.0;
			this.body.SetBullet(false);
			this.IsTouching = false;

			

		};
		enemy.prototype.move = function() {
			var vel = this.body.GetLinearVelocity();

			if( Math.abs(vel.x) < this.minVelocity ) {
				if( vel.x >= 0)
					vel.x = this.minVelocity;
				else 
					vel.x = -1 * this.minVelocity;
			}

			var edgecount = 0;
				
			var worldpoint = this.body.GetWorldCenter();
			var contact_edge = this.body.GetContactList();
			if( contact_edge != null) {
				while( contact_edge != null  ) {
					var contact = contact_edge.contact;	
					var a = contact.GetFixtureA();
					var b = contact.GetFixtureB();
					
					if( a.GetUserData() != "ground" && b.GetUserData() != "ground" ) {

						// debug
						
						var worldmanifold = new b2WorldManifold();
						contact.GetWorldManifold(worldmanifold);
						var normal = worldmanifold.m_points;

						for(var i=0; i< normal.length; i++ ) {
							var point = normal[i];
							if( point.x != 0 && point.y != 0 ) {
								var worldcenter = this.body.GetWorldCenter();
								console.log("worldcenter: " + (worldpoint.x*worldscale) + ", " + (worldpoint.y*worldscale) );
								console.log("linear velocity: " + (vel.x*worldscale) + ", " + (vel.y*worldscale) );
								console.log("edge #" + edgecount + ", point #" + i + ": " + (point.x * worldscale) + ", " + (point.y * worldscale));
								
								if( (point.x - worldcenter.x ) > 0 ) {
									if( vel.x > 0 ) {
										if( contact.IsTouching() && this.IsTouching == false ) {
											this.IsTouching = true;
											vel.x = vel.x * -1;
										}

										if( this.IsTouching == true && contact.IsTouching() == false ) {
											this.IsTouching = false;
										}
									}
								} else {
									if( vel.x < 0 ) {
										if( contact.IsTouching() && this.IsTouching == false ) {
											this.IsTouching = true;
											vel.x = vel.x * -1;
										}

										if( this.IsTouching == true && contact.IsTouching() == false ) {
											this.IsTouching = false;
										}
									}
								}
							}
						}

						// end debug
							
					}
					contact_edge = contact_edge.next;
					edgecount++;
				}
			}

			if( vel.y > 0.1 ) {
				vel.x = 0;
				this.body.SetLinearVelocity(vel);
			}
			
		}
		
		var player1 = new player();

		var enemy1 = new enemy(canvas_x/4/worldscale,canvas_y/2/worldscale);	

		// define & construct contact listener

		var debugDraw = new b2DebugDraw();
			debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));
			debugDraw.SetDrawScale(worldscale);
			debugDraw.SetLineThickness(1.0);
			debugDraw.SetFillAlpha(0.5);
			debugDraw.SetFlags( b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
			world.SetDebugDraw(debugDraw);
 

		var updateInterval = window.setInterval(update, 1000/100);
		
		var listener = new b2ContactListener;
		listener.BeginContact = function(contact) {
			var a = contact.GetFixtureA().GetUserData();
			var b = contact.GetFixtureB().GetUserData();;
			if( a == "player" || b == "player" ) {
				player1.canJump = true;
			}
		};
		listener.EndContact = function(contact) {
			var a = contact.GetFixtureA().GetUserData();
			var b = contact.GetFixtureB().GetUserData();;
			if( a == "player" || b == "player" ) {
				player1.canJump = false;
			}
		};
		listener.PostSolve = function( contact, manifold ) {
			var a = contact.GetFixtureA().GetUserData();
			var b = contact.GetFixtureB().GetUserData();
		};
		world.SetContactListener(listener);


		var keys = [];

		var scrollscale = 1;

		$('#canvas').mouseover(function(e) {
			$(this).scroll( function(e) {
				e.preventDefault();
				console.log("howdy");
			})
		}).mouseout(function(){
			$(this).unbind('scroll');
			
		});

		document.addEventListener("keydown",function(e) {
			keys[e.keyCode] = true;
			if( keys[32] ) {
				if( updateInterval != null ) {
					clearInterval(updateInterval);
					updateInterval = null;
				} else {
					updateInterval = window.setInterval(update, 1000/60);
				}
			}
		});
		document.addEventListener("keyup",function(e) {
			keys[e.keyCode] = false;
		});
		var canvasPosition = getElementPosition(document.getElementById("canvas"));
		document.addEventListener("mousemove", function(e) {

			var mouseX = new Number((e.clientX - canvasPosition.x)/worldscale);
			var mouseY = new Number((e.clientY - canvasPosition.y)/worldscale);
			$('#mousedebug').html("x:"+ mouseX.toPrecision(4) + " y: " + mouseY.toPrecision(4));
		});

		var offsetX = 0;
		var lastX = null;
		var steps = 0;
		
		function update() {
		
			// clear canvas of shape artifacts
			var canvas = document.getElementById("canvas");	
			canvas.getContext("2d").clearRect( 
				-1 * world_width * worldscale,
				-1 * worldscale, 
				4 * world_width * worldscale,
				2 * world_height * worldscale);
			world.Step(1/100,10,10);
			world.DrawDebugData();
			world.ClearForces();



			// handle side-scroll
			steps += 0.001;
			if( lastX != null) {
				var x = player1.body.GetPosition().x;
				var translateX = (lastX - x) * worldscale;
				offsetX += translateX;
				if( x > canvas_x/2/worldscale && x <= world_width - canvas_x/2/worldscale) {
					canvas.getContext("2d").translate(translateX,0);
				}
				lastX = x;
			}

			player1.move();	
			enemy1.move();
			

		};

	};

	function log(str) {
		$('#debug').append(str +" <br>");
		$('#debug').scrollTop(99999);
	};

	//helpers
         
         //http://js-tut.aardon.de/js-tut/tutorial/position.html
         function getElementPosition(element) {
            var elem=element, tagname="", x=0, y=0;
           
            while((typeof(elem) == "object") && (typeof(elem.tagName) != "undefined")) {
               y += elem.offsetTop;
               x += elem.offsetLeft;
               tagname = elem.tagName.toUpperCase();

               if(tagname == "BODY")
                  elem=0;

               if(typeof(elem) == "object") {
                  if(typeof(elem.offsetParent) == "object")
                     elem = elem.offsetParent;
               }
            }

            return {x: x, y: y};
         }

	</script>
</html>
